<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>风机Demo</title>
    <style>
      body {
        margin:0;
        overflow: hidden;
        color: #FFF;
        position: relative
        /* 隐藏body窗口区域滚动条 */
      }
      .header-box{
        width: 100%;
        height: 126px;
        position:absolute;
        background: url(./assets/images/header-bg.png) no-repeat;
        background-size: 100% 100%;
        top: -30px;
        z-index: 200;
      }
      .titile{
        font-size: 36px;
        margin-top: 40px;
        font-weight: 500;
        font-family: FZLanTingHeiS-B-GB;
        text-align: center;
      }
      .echarts-box{
        height: 28vh;
        width: 35.08vw;
        left: 20px;
        bottom: 40px;
        position:absolute
      }
      .equipmentLabel {
        z-index: 999;
        width: 988px;
        height: 451px;
      }
      .equipmentLabel > li:nth-child(1) {
        color: transparent;
        width: 191px;
        height: 225px;
        background-image: url("./assets/images/1.png");
        background-size: 191px auto;
        position: absolute;
        right: 302px;
        top: 0;
      }
      .equipmentLabel .labelInfo {
        color: transparent;
        width: 302px;
        height: 225px;
        background-image: url("./assets/images/2.png");
        background-size: 302px auto;
        position: absolute;
        right: 0;
        top: 0;
        padding: 10px;
        box-sizing: border-box;
      }
      .equipmentLabel .labelInfo > div {
        width: 100%;
        height: 100%;
        background-color: #04669e73;
        border: 1px solid #15c5e8;
        box-sizing: border-box;
        padding: 20px 20px;
      }
      .equipmentLabel .labelInfo > div header {
        width: 100%;
        text-align: left;
        font-size: 14px;
        line-height: 20px;
        color: #fff;
        border-bottom: 1px dashed aqua;
        padding-bottom: 14px;
      }
      .equipmentLabel .labelInfo > div header .en {
        font-size: 12px;
        color: aqua;
      }
      .equipmentLabel .labelInfo > div ul {
        width: 100%;
        color: #fff;
      }
      .equipmentLabel .labelInfo > div ul li {
        line-height: 30px;
        font-size: 14px;
        display: flex;
        text-align: left;
        align-items: center;
      }

      .equipmentLabel .labelInfo > div ul li span:nth-child(1) {
        width: 40%;
      }
      .equipmentLabel .labelInfo > div ul li span:nth-child(2) {
        width: 15%;
        color: #f0c002;
        text-align: right;
        margin-right: 10px;
      }
      .equipmentLabel .labelInfo > div ul li span:nth-child(3) {
        width: 30%;
      }
    </style>
    <!-- 引入echarts文件 -->
    <script src="./assets/js/echarts.min.js"></script>
  </head>

  <body>
    <div class="header-box">
      <div class="titile">智慧风机监测系统</div>
    </div>
    <div class="echarts-box"></div>
    <!-- 我们将把three.js渲染的效果显示在这个div中，div为容器 -->
    <div id="puiedu-webgl-output" >

    </div>
    <!-- 2D信息弹窗 -->
    <ul id='equipmentLabelRef' class='equipmentLabel' >
      <li></li>
      <li class='labelInfo' >
          <div>
              <header>
                  <div id="cn">{labelData.cn}</div>
                  <span id="en">{labelData.en}</span>
              </header>
              <ul id="valueUl">
              </ul>
          </div>
      </li>
    </ul>
    

    <script type="module">
      import * as THREE from "../src/Three.js"
      import { GLTFLoader } from '../jsm/loaders/GLTFLoader.js';
      import { OrbitControls } from '../jsm/controls/OrbitControls.js';
      //后处理js
      // EffectComposer(效果组合器)对象
      import { EffectComposer } from '../jsm/postprocessing/EffectComposer.js'
      // RenderPass该通道在指定的场景和相机的基础上渲染出一个新场景
      import { RenderPass } from '../jsm/postprocessing/RenderPass.js'
      import { OutlinePass } from '../jsm/postprocessing/OutlinePass.js'
      //2D信息
      import {CSS2DRenderer,CSS2DObject} from "../jsm/renderers/CSS2DRenderer.js";
      //导入模拟数据
      import {labelData} from './assets/labelData/labelData.js'

      /*
      *定义变量
      */
      const scale = 0.0003
      let size = {
        w: window.innerWidth,
        h: window.innerHeight
      }
      
      //存储各个部件
      let equipmentMaterialMap = new Map()
      //风机涡轮转动参数
      let matrixTurbine = null
      //颜色材质
      let metal = null
      //线框材质
      let wireframe = null
      //动画帧
      let mixers = new Map()
      //创建一个动画时钟对象Clock
      let clock = new THREE.Clock()
      let mixer = null

      /*
      *点击事件相关变量
      */
      //获取所有内部结构网格对象，用于判断射线相交对象
      let equipment = null
      //鼠标点击-屏幕坐标
      let mouse = new THREE.Vector2();
      //用于检测的射线
      let raycaster = new THREE.Raycaster();
      //效果组合
      let compose = null
      //弹出信息框总数据
      let equipmentLabelData = labelData()[0]
      //当前选中模型的数据
      let nowLabelData = null
      let labelCSS2D = null

      
      //创建场景对象
      var scene = new THREE.Scene()
      //创建相机
      var camera = createdCamera(30, size.w, size.h, [-4, -3.5, 4], 1)
      //创建光源
      createdLight()
      //创建渲染器
      var renderer = createdRender()
      //信息窗2D渲染器
      let labelRenderer = createTurbineLabel()
      
      // 辅助坐标系 参数250表示坐标系大小，可以根据场景大小去设置
      // var axesHelper = new THREE.AxesHelper(250)
      // scene.add(axesHelper)

      //加载地板
      loadPlane()
      //加载内部结构
      loadEquipment()
      //加载外壳涡轮
      loadTurbine()
      
      //执行渲染
      render()
      //鼠标操作
      mouseMove()
      

      /*
      *创建相机
      */
      function createdCamera(fov,width,height,position,zoom){
        var camera = new THREE.PerspectiveCamera(fov,width/height,0.1,1000,zoom)
        camera.position.set(position[0],position[1],position[2])
        return camera
      }

      /*
      *创建光源
      */
      function createdLight(){
        const arr = [
          [100,100,100],
          [-100,100,100],
          [100,-100,100]
        ]
        arr.forEach(lightArr=>{
          let spotLight = new THREE.DirectionalLight(0xffffff,3)
          let [x,y,z] = lightArr
          spotLight.position.set(x, y, z);
          scene.add(spotLight);
        })
      }

      //渲染器
      function createdRender() {
        let renderer = new THREE.WebGLRenderer({antialias: true, alpha: true})
        renderer.shadowMap.enabled = true
        renderer.setSize(size.w,size.h)
        renderer.setClearColor(0x030B1A)
        //获取容器，并加入渲染器
        document.getElementById('puiedu-webgl-output').appendChild(renderer.domElement)
        return renderer
      }
      
      //加载地板
      function loadPlane(){
        const loader = new GLTFLoader();
        loader.load('assets/models/plane.glb',(obj)=>{
          let mesh = obj.scene
          mesh.scale.set(scale,scale,scale)
          mesh.position.set(0,-2,0)
          scene.add(mesh)
        })
      }

      //加载内部结构
      function loadEquipment(){
        const loader = new GLTFLoader();
        loader.load('assets/models/equipment.glb',(obj)=>{
          let mesh = obj.scene
          mesh.name = 'equipment'
          //将网格对象给equipment，用于鼠标点击时检测与射线相交的物体
          equipment = mesh
          console.log("内部结构equipment",equipment)
          mesh.traverse(child =>{
            if (child.isMesh) {
              child.material = child.material.clone()
              equipmentMaterialMap.set(child.name,child)
            }
          })
          mesh.scale.set(scale,scale,scale)
          mesh.position.set(0,-2,0)
          scene.add(mesh)
        })
      }

      //加载外壳涡轮
      function loadTurbine(){
        const loader = new GLTFLoader();
        if (scene.getObjectByName('turbine')) {
          let removeTurbine = scene.getObjectByName('turbine')
          scene.remove(removeTurbine)
        }
        loader.load('assets/models/turbine.glb',(obj)=>{
          console.log("模型",obj)
          matrixTurbine = obj
          let mesh = obj.scene
          mesh.name = 'turbine'
          metal = mesh.getObjectByName('颜色材质')
          wireframe = mesh.getObjectByName('线框材质')
          //设置颜色材质的显示和隐藏
          metal.visible = false

          mesh.scale.set(scale, scale, scale)
          mesh.position.set(0,-2,0)
          scene.add(mesh)
          changeAnimation(mesh,'Anim_0')
        })
      }

      //风机旋转动画
      function changeAnimation(turbine,animationName){
        const animations = matrixTurbine.animations
        //创建混合器，播放turbine包含的帧动画数据
        mixer = new THREE.AnimationMixer(turbine)
        //AnimationClip 是一组可重复使用的关键帧轨迹，代表一个动画
        const clip = THREE.AnimationClip.findByName(animations,animationName)
        const key = "AA"
        if (clip) {
          const action = mixer.clipAction(clip)
          action.play()
          mixers.set(key, mixer)
        }else{
          mixers.delete(key)
        }
      }

      //鼠标点击事件
      function onPointerClick(event) {
        const [w,h] = [window.innerWidth,window.innerHeight]
        mouse.x = (event.clientX / w) * 2 - 1
        mouse.y = -(event.clientY / h) * 2 + 1
        //更新射线
        raycaster.setFromCamera(mouse, camera)
        console.log('参数',equipment)
        //返回被击中的信息
        const intersects = raycaster.intersectObject(equipment, true)
        if (intersects.length <= 0) {
            return false;
        }
        const selectedObject = intersects[0].object
        if (selectedObject.isMesh) {
          outline([selectedObject])
          //显示弹窗
          updateLabel(intersects[0],equipmentLabelData[selectedObject.name])
        }
      }

      //点击后高亮线框渲染
      function outline(selectedObjects,color = 0x15c5e8) {
        const [w,h] = [window.innerWidth,window.innerHeight]
        //RenderPass这个通道会渲染场景，但不会将渲染结果输出到屏幕上
        let renderPass = new RenderPass(scene,camera)
        //高亮数据
        let outlinePass = new OutlinePass(
          new THREE.Vector2(w,h),//分辨率
          scene,
          camera,
          selectedObjects//选中的物体对象，传入需要边界线进行高亮处理的对象
        )
        outlinePass.renderToScreen = true
        outlinePass.selectedObjects = selectedObjects
        outlinePass.edgeStrength = 3//粗
        outlinePass.edgeGlow = 0//发光
        outlinePass.visibleEdgeColor.set(color);//设置显示的颜色
        outlinePass.hiddenEdgeColor.set(color);//设置隐藏的颜色

        //创建效果组合器对象，可以在该对象上添加后期处理通道，通过配置该对象， 
        //使它可以渲染我们的场景，并应用额外的后期处理步骤，在render循环中，
        //使用EffectComposer渲染场景、应用通道，并输出结果
        compose = new EffectComposer(renderer)

        compose.addPass(renderPass)
        compose.addPass(outlinePass)
        compose.render(scene,camera)
      }

      //创建2D信息窗
      function createTurbineLabel(){
        let labelRenderer = new CSS2DRenderer();
        labelRenderer.setSize( window.innerWidth, window.innerHeight );
        labelRenderer.domElement.style.position = 'absolute';
        labelRenderer.domElement.style.top = '0px';
        document.body.appendChild( labelRenderer.domElement );
        labelCSS2D = new CSS2DObject(document.getElementById('equipmentLabelRef'));
        scene.add(labelCSS2D);
        labelCSS2D.visible = false
        return labelRenderer
        // labelCSS2D.element.addEventListener('click',()=>{
        //   consoe.log("dianji")
        //   labelCSS2D.visible = false
        // })
      }

      //更新信息窗位置
      function updateLabel(intersect,labelData){
        var cnDiv = document.getElementById('cn')
        cnDiv.innerHTML = labelData.cn
        var enDiv = document.getElementById('en')
        enDiv.innerHTML = labelData.en
        var str = ""
        labelData.list.forEach(item=>{
          str+= `<li>
                    <span>${item.name}</span>
                    <span>${item.value}</span>
                    <span>${item.unit}</span>
                </li>`
        })
        document.getElementById('valueUl').innerHTML=str
        const point = intersect.point;
        labelCSS2D.position.set(point.x-0.01, point.y+0.01, point.z-0.03);
        labelCSS2D.visible = true
      }

      /*
      *执行渲染 
      */
      function render(){
        //执行渲染操作
        if (scene && camera) {
          renderer.render(scene,camera)
          labelRenderer.render(scene,camera)
        }
        // 用于跟踪时间的对象
        const delta = new THREE.Clock().getDelta(); //获取自设置 oldTime 时间以来经过的秒数，并将 oldTime 设置为当前时间，在此delta基本为0
        if (compose) {
          compose.render(delta);
        }
        requestAnimationFrame(render)
        //获得两帧的时间间隔
        const mixerUpdateDelta = clock.getDelta();
        //更新混合器相关的时间
        mixers.forEach(mixer =>{
          mixer.update(mixerUpdateDelta)
        })
      }

      /*
      *鼠标操作-放大、缩小、旋转
      */
      function mouseMove(){
        //创建控件对象
        var controls = new OrbitControls(camera,labelRenderer.domElement)
        //初始化鼠标点击事件
        document.addEventListener("click", onPointerClick);
      }

      /*
      *三维场景自适应
      */
      window.addEventListener('resize',onWindowResize,false)
      function onWindowResize(){
        camera.aspect = window.innerWidth/window.innerHeight
        camera.updateProjectionMatrix()
        renderer.setSize(window.innerWidth,window.innerHeight)
        labelRenderer.setSize( window.innerWidth, window.innerHeight );
      }
    </script>

    <script type="module">
      //初始化echarts实例
      var myChart = echarts.init(document.querySelector(".echarts-box"))
      //制定图表的配置项和数据
      var options = {
        title: {
          text: '风机功率和风速折线图',
          textStyle:{
            color:'#fffff0',
            fontSize : 16,
          },
          left : 5
        },
        tooltip: {
          trigger: "axis",
        },
        legend: {
          textStyle:{
            color:'#ffffff'
          },
          data: ['功率', '风速']
        },
        grid: {
          left: 10,
          right: 10,
          bottom: 20,
          top: 30,
          containLabel: true,
        },
        xAxis: {
          name: "时间/小时",
          type: "category",
          // boundaryGap: false,
          data: ["1", "3", "5", "7", "9", "11", "13","15", "17", "19", "21", "23"],
          axisLine: {
            // show: false,
            lineStyle: {
              color: "#028ab5ad",
            },
          },
        },
        yAxis: {
          // name: "风速/功率",
          type: "value",
          axisLine: {
            show: false,
            lineStyle: {
              color: "#028ab5ad",
            },
          },

          splitLine: {
            lineStyle: {
              color: ["#028ab545"],
            },
          },
        },
        series: [
          {
            name: "功率",
            type: "line",
            data: [12, 6, 13, 5, 18, 15, 8,2, 4, 12, 15, 10],
            lineStyle: {
              color: "#15c5e8",
            },
            itemStyle: {
              normal: {
                color: "#15c5e8",
              },
            },
          },
          {
            name: "风速",
            type: "line",
            // stack: "总量",
            data: [2, 4, 12, 15, 10, 11, 5,12, 6, 13, 5, 18],
            lineStyle: {
              color: "#c8a818",
            },
            itemStyle: {
              normal: {
                color: "#c8a818",
              },
            },
          },
        ],
      }
      //使用刚指定的配置项和数据显示图表
      myChart.setOption(options)
    </script>
    
  </body>

</html>